package com.ozo.cloud.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ozo.cloud.api.manage.vo.*;
import com.ozo.cloud.common.base.model.BasePage;
import com.ozo.cloud.common.base.model.BaseBatchDTO;
import com.ozo.cloud.common.base.model.PageResult;
import com.ozo.cloud.common.core.exception.ServiceException;
import com.ozo.cloud.common.database.util.SortUtils;
import com.ozo.cloud.common.satoken.context.UserLoginHelper;
import com.ozo.cloud.manage.entity.SysUserPostRel;
import com.ozo.cloud.manage.exception.ManageExceptionEnum;
import com.ozo.cloud.manage.pojo.dto.*;
import com.ozo.cloud.manage.entity.SysDept;
import com.ozo.cloud.manage.entity.SysUser;
import com.ozo.cloud.manage.entity.SysUserRoleRel;
import com.ozo.cloud.manage.mapper.SysDeptMapper;
import com.ozo.cloud.manage.mapper.SysUserMapper;
import com.ozo.cloud.manage.pojo.vo.SysPermissionVO;
import com.ozo.cloud.manage.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户 服务实现类
 * </p>
 *
 * @author qiangesoft
 * @since 2024-07-11
 */
@RequiredArgsConstructor
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements ISysUserService {

    private final SysDeptMapper sysDeptMapper;

    private final ISysRoleService sysRoleService;

    private final ISysUserRoleRelService sysUserRoleRelService;

    private final ISysPostService sysPostService;

    private final ISysUserPostRelService sysUserPostRelService;

    private final ISysPermissionService sysPermissionService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(SysUserSaveDTO saveDTO) {
        // 合法性校验
        this.checkParam(saveDTO);

        // 用户信息
        SysUser sysUser = BeanUtil.copyProperties(saveDTO, SysUser.class);
        sysUser.setPassword(SecureUtil.md5(saveDTO.getPassword()));
        baseMapper.insert(sysUser);

        // 用户角色关系
        Long userId = sysUser.getId();
        List<Long> roleIdList = saveDTO.getRoleIdList();
        List<SysUserRoleRel> sysUserRoleRelList = new ArrayList<>();
        for (Long roleId : roleIdList) {
            SysUserRoleRel sysUserRoleRel = new SysUserRoleRel();
            sysUserRoleRel.setUserId(userId);
            sysUserRoleRel.setRoleId(roleId);
            sysUserRoleRelList.add(sysUserRoleRel);
        }
        sysUserRoleRelService.saveBatch(sysUserRoleRelList);

        // 用户岗位关系
        List<Long> postIdList = saveDTO.getPostIdList();
        if (CollUtil.isNotEmpty(postIdList)) {
            List<SysUserPostRel> sysUserPostRelList = new ArrayList<>();
            for (Long postId : postIdList) {
                SysUserPostRel sysUserPostRel = new SysUserPostRel();
                sysUserPostRel.setUserId(userId);
                sysUserPostRel.setPostId(postId);
                sysUserPostRelList.add(sysUserPostRel);
            }
            sysUserPostRelService.saveBatch(sysUserPostRelList);
        }
    }

    /**
     * 合法性校验
     *
     * @param saveDTO
     */
    private void checkParam(SysUserSaveDTO saveDTO) {
        Long id = saveDTO.getId();

        LambdaQueryWrapper<SysUser> usernameQueryWrapper = new LambdaQueryWrapper<>();
        usernameQueryWrapper.eq(SysUser::getUsername, saveDTO.getUsername())
                .ne(Objects.nonNull(id), SysUser::getId, id);
        Long usernameCount = baseMapper.selectCount(usernameQueryWrapper);
        if (usernameCount > 0) {
            throw new ServiceException(ManageExceptionEnum.USERNAME_EXISTS);
        }

        LambdaQueryWrapper<SysUser> mobileQueryWrapper = new LambdaQueryWrapper<>();
        mobileQueryWrapper.eq(SysUser::getMobile, saveDTO.getMobile())
                .ne(Objects.nonNull(id), SysUser::getId, id);
        Long mobileCount = baseMapper.selectCount(mobileQueryWrapper);
        if (mobileCount > 0) {
            throw new ServiceException(ManageExceptionEnum.MOBILE_EXISTS);
        }
    }

    @Override
    public void remove(BaseBatchDTO<Long> batchDTO) {
        baseMapper.deleteBatchIds(batchDTO.getIdList());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(SysUserSaveDTO saveDTO) {
        // 合法性校验
        this.checkParam(saveDTO);

        // 用户信息
        SysUser sysUser = BeanUtil.copyProperties(saveDTO, SysUser.class);
        sysUser.setPassword(SecureUtil.md5(saveDTO.getPassword()));
        baseMapper.updateById(sysUser);

        // 用户角色关系
        Long userId = sysUser.getId();
        LambdaQueryWrapper<SysUserRoleRel> userRoleRelQueryWrapper = new LambdaQueryWrapper<>();
        userRoleRelQueryWrapper.eq(SysUserRoleRel::getUserId, userId);
        sysUserRoleRelService.remove(userRoleRelQueryWrapper);
        List<Long> roleIdList = saveDTO.getRoleIdList();
        List<SysUserRoleRel> sysUserRoleRelList = new ArrayList<>();
        for (Long roleId : roleIdList) {
            SysUserRoleRel sysUserRoleRel = new SysUserRoleRel();
            sysUserRoleRel.setUserId(userId);
            sysUserRoleRel.setRoleId(roleId);
            sysUserRoleRelList.add(sysUserRoleRel);
        }
        sysUserRoleRelService.saveBatch(sysUserRoleRelList);

        // 用户岗位关系
        LambdaQueryWrapper<SysUserPostRel> userPostRelQueryWrapper = new LambdaQueryWrapper<>();
        userPostRelQueryWrapper.eq(SysUserPostRel::getUserId, userId);
        sysUserPostRelService.remove(userPostRelQueryWrapper);
        List<Long> postIdList = saveDTO.getPostIdList();
        if (CollUtil.isNotEmpty(postIdList)) {
            List<SysUserPostRel> sysUserPostRelList = new ArrayList<>();
            for (Long postId : postIdList) {
                SysUserPostRel sysUserPostRel = new SysUserPostRel();
                sysUserPostRel.setUserId(userId);
                sysUserPostRel.setPostId(postId);
                sysUserPostRelList.add(sysUserPostRel);
            }
            sysUserPostRelService.saveBatch(sysUserPostRelList);
        }
    }

    @Override
    public PageResult<SysUserVO> page(BasePage basePage, SysUserQueryDTO queryDTO) {
        Integer pageNum = basePage.getPageNum();
        Integer pageSize = basePage.getPageSize();

        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        // 排序
        String order = basePage.getOrder();
        if (StrUtil.isBlank(order)) {
            queryWrapper.lambda().orderByDesc(SysUser::getId);
        } else {
            SortUtils.setSortCondition(queryWrapper, basePage.getProp(), order);
        }
        // 条件
        queryWrapper.lambda()
                .eq(Objects.nonNull(queryDTO.getDeptId()), SysUser::getDeptId, queryDTO.getDeptId())
                .eq(StrUtil.isNotBlank(queryDTO.getStatus()), SysUser::getStatus, queryDTO.getStatus())
                .and(StrUtil.isNotBlank(queryDTO.getKeyword()),
                        e -> e.like(SysUser::getUsername, queryDTO.getKeyword())
                                .or().like(SysUser::getNickname, queryDTO.getKeyword())
                                .or().like(SysUser::getMobile, queryDTO.getKeyword()));
        Page<SysUser> page = baseMapper.selectPage(new Page<>(pageNum, pageSize), queryWrapper);

        PageResult<SysUserVO> pageResult = new PageResult<>();
        pageResult.setPageNum(pageNum);
        pageResult.setPageSize(pageSize);
        pageResult.setPage(page.getPages());
        pageResult.setTotal(page.getTotal());
        List<SysUser> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            pageResult.setResults(List.of());
            return pageResult;
        }

        List<Long> userIdList = records.stream().map(SysUser::getId).collect(Collectors.toList());
        List<SysUserVO> recordVOList = BeanUtil.copyToList(records, SysUserVO.class);

        // 所属角色
        Map<Long, List<SysRoleVO>> userRoleMap = sysRoleService.listByUserIds(userIdList);
        recordVOList.forEach(e -> e.setRoleList(userRoleMap.get(e.getId())));

        // 所属岗位
        Map<Long, List<SysPostVO>> userPostMap = sysPostService.listByUserIds(userIdList);
        recordVOList.forEach(e -> e.setPostList(userPostMap.get(e.getId())));

        // 所属部门
        Set<Long> deptIdSet = records.stream().map(SysUser::getDeptId).collect(Collectors.toSet());
        List<SysDept> sysDeptList = sysDeptMapper.selectBatchIds(deptIdSet);
        List<SysDeptVO> sysDeptVOList = BeanUtil.copyToList(sysDeptList, SysDeptVO.class);
        Map<Long, SysDeptVO> deptVOMap = sysDeptVOList.stream().collect(Collectors.toMap(SysDeptVO::getId, sysDeptVO -> sysDeptVO));
        recordVOList.forEach(e -> e.setDept(deptVOMap.get(e.getDeptId())));

        pageResult.setResults(recordVOList);
        return pageResult;
    }

    @Override
    public void resetPwd(BaseBatchDTO<Long> batchDTO) {
        LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(SysUser::getId, batchDTO.getIdList())
                .set(SysUser::getPassword, "123456");
        baseMapper.update(updateWrapper);
    }

    @Override
    public void changeStatus(ChangeStatusDTO statusDTO) {
        LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(SysUser::getId, statusDTO.getId())
                .set(SysUser::getStatus, statusDTO.getStatus());
        baseMapper.update(updateWrapper);
    }

    @Override
    public SysUserInfoVO getByUsername(String username) {
        SysUser sysUser = this.lambdaQuery().eq(SysUser::getUsername, username).one();
        if (sysUser == null) {
            return null;
        }
        SysUserInfoVO sysUserVO = new SysUserInfoVO();
        BeanUtil.copyProperties(sysUser, sysUserVO);

        Long userId = sysUserVO.getId();
        Set<String> roles = sysRoleService.listByUserId(userId).stream().map(SysRoleVO::getRoleCode).collect(Collectors.toSet());
        sysUserVO.setRoles(roles);
        Set<String> permissions = sysPermissionService.listPermissionByUserId(userId).stream().map(SysPermissionVO::getCode).collect(Collectors.toSet());
        sysUserVO.setPermissions(permissions);

        return sysUserVO;
    }

    @Override
    public SysUserInfoVO getByMobile(String mobile) {
        SysUser sysUser = this.lambdaQuery().eq(SysUser::getMobile, mobile).one();
        if (sysUser == null) {
            return null;
        }
        SysUserInfoVO sysUserVO = new SysUserInfoVO();
        BeanUtil.copyProperties(sysUser, sysUserVO);

        Long userId = sysUserVO.getId();
        Set<String> roles = sysRoleService.listByUserId(userId).stream().map(SysRoleVO::getRoleCode).collect(Collectors.toSet());
        sysUserVO.setRoles(roles);
        Set<String> permissions = sysPermissionService.listPermissionByUserId(userId).stream().map(SysPermissionVO::getCode).collect(Collectors.toSet());
        sysUserVO.setPermissions(permissions);

        return sysUserVO;
    }

    @Override
    public SysUserInfoVO getByUserId(Long id) {
        SysUser sysUser = baseMapper.selectById(id);
        if (sysUser == null) {
            return null;
        }
        SysUserInfoVO sysUserVO = new SysUserInfoVO();
        BeanUtil.copyProperties(sysUser, sysUserVO);
        return sysUserVO;
    }

    @Override
    public List<SysUserInfoVO> listAll() {
        List<SysUser> sysUserList = this.list();
        return BeanUtil.copyToList(sysUserList, SysUserInfoVO.class);
    }

    @Override
    public void updatePwd(UserPasswordDTO passwordDTO) {
        String password = passwordDTO.getPassword();
        String newPassword = passwordDTO.getNewPassword();
        String confirmNewPassword = passwordDTO.getConfirmNewPassword();
        if (!newPassword.equals(confirmNewPassword)) {
            throw new ServiceException(ManageExceptionEnum.TWO_PASSWORD_NOT_MATCH);
        }

        Long userId = UserLoginHelper.getUserId();
        SysUser sysUser = baseMapper.selectById(userId);

        String md5 = SecureUtil.md5(password);
        if (!md5.equals(sysUser.getPassword())) {
            throw new ServiceException(ManageExceptionEnum.OLD_PASSWORD_NOT_RIGHT);
        }

        sysUser.setPassword(SecureUtil.md5(newPassword));
        baseMapper.updateById(sysUser);
    }

    @Override
    public void updateInfo(UserEditDTO editDTO) {
        Long count = this.lambdaQuery().eq(SysUser::getMobile, editDTO.getMobile())
                .ne(SysUser::getId, editDTO.getId()).count();
        if (count > 0) {
            throw new ServiceException(ManageExceptionEnum.MOBILE_EXISTS);
        }

        SysUser sysUser = BeanUtil.copyProperties(editDTO, SysUser.class);
        baseMapper.updateById(sysUser);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void register(String username, String password, String nickname) {
        LambdaQueryWrapper<SysUser> usernameQueryWrapper = new LambdaQueryWrapper<>();
        usernameQueryWrapper.eq(SysUser::getUsername, username)
                .or().eq(SysUser::getMobile, username);
        Long usernameCount = baseMapper.selectCount(usernameQueryWrapper);
        if (usernameCount > 0) {
            throw new ServiceException(ManageExceptionEnum.MOBILE_EXISTS);
        }

        SysUser sysUser = new SysUser();
        sysUser.setUsername(username);
        sysUser.setPassword(SecureUtil.md5(password));
        sysUser.setNickname(nickname);
        sysUser.setDeptId(1L);
        sysUser.setStatus("1");
        baseMapper.insert(sysUser);

        SysUserRoleRel sysUserRoleRel = new SysUserRoleRel();
        sysUserRoleRel.setUserId(sysUser.getId());
        sysUserRoleRel.setRoleId(2L);
        sysUserRoleRelService.save(sysUserRoleRel);
    }

}
